{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Attacking AES Without A Trigger"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**This tutorial can only be completed using the [CW1200 ChipWhisperer Pro](https://wiki.newae.com/CW1200_ChipWhisperer-Pro)**\n",
    "\n",
    "Throughout all of our tutorials, we've been relying on our target to provide a nice rising edge trigger for us to start our ADC capture on. As you might expect, this isn't something we can rely on in a real attack. This tutorial will focus on using two of the ChipWhisperer Pro's exclusive features, stream mode and the Sum of Absolute Difference (SAD) module, to break a more realistic target.\n",
    "\n",
    "As usual, we'll start by setting up the firmware for the target.\n",
    "\n",
    "If you want to *totally* remove the trigger, navigate to `../../firmware/mcu/simpleserial-aes` and open `simpleserial-aes.c` in your favourite text editor. Find the following code and comment out `trigger_high();` and `trigger_low();`:\n",
    "\n",
    "```C\n",
    "uint8_t get_pt(uint8_t* pt)\n",
    "{\n",
    "\ttrigger_high();\n",
    "\taes_indep_enc(pt); /* encrypting the data block */\n",
    "\ttrigger_low();\n",
    "\tsimpleserial_put('r', 16, pt);\n",
    "\treturn 0x00;\n",
    "}\n",
    "```\n",
    "\n",
    "Then build the firmware:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "SCOPETYPE = 'OPENADC'\n",
    "PLATFORM = 'CWLITEXMEGA'\n",
    "CRYPTO_TARGET = 'AVRCRYPTOLIB'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%bash -s \"$PLATFORM\" \"$CRYPTO_TARGET\"\n",
    "cd ../../firmware/mcu/simpleserial-aes\n",
    "make PLATFORM=$1 CRYPTO_TARGET=$2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## The plan"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "With your experience with the ChipWhisperer and power analysis attacks up to this point, you might expect that without those `trigger_high();` and `trigger_low();` calls, attacking this target will be extremely difficult. In reality, with the ChipWhisperer Pro, we can boil this down into a simple two step plan:\n",
    "\n",
    "1. Use the Pro's stream mode feature to record a power wave that will encompass a long peroid of the target's operation (say a tenth of a second)\n",
    "1. Find where AES is happening and use it as a reference for the SAD module. This module allows the ChipWhisperer to trigger based on a 128 sample long unique portion of a power wave and will replace the rising edge trigger we had in earlier tutorials.\n",
    "\n",
    "More details about what stream mode and SAD do and their limitations will be explained as we go through the tutorial. With that said, let's get to work on implementing this plan!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Setup and Stream Mode"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To start, we'll setup the scope as usual:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%run \"../Setup_Scripts/Setup_Generic.ipynb\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "And program the device:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fw_path = '../../firmware/mcu/simpleserial-aes/simpleserial-aes-{}.hex'.format(PLATFORM)\n",
    "cw.program_target(scope, prog, fw_path)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Next, let's get into what stream mode is. Essentially, stream mode allows the ChipWhisperer software to continuously read power measurements back from the scope enabling extremely long captures. In theory, there's no limit to how long these captures can be, but keep in mind very long wave (in the millions of samples) can easily outstrip your computer's memory. Even if you can store the wave itself, doing anything else with the wave may cause memory errors.\n",
    "\n",
    "Stream mode does have one major limit though: sample rate. With stream mode enabled, the Pro can only record traces at a sample rate of less than 10MHz. Our typical 4\\*7.37MHz ADC clock easily outpaces that, so we'll need to change our clocksource to be 7.37MHz instead:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.clock.adc_src = \"clkgen_x1\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Stream mode itself is pretty easy to enable:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.adc.stream_mode = True"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We'll need to set our regular trigger to be `\"low\"` so that the scope will immediately trigger and start capturing after being armed:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.adc.basic_mode = \"low\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can now set the number of samples to capture to be much higher. Let's set it to 1M traces, just to be safe:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.adc.samples=1000000"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "That's it! We can now capture a very long trace (give this one a second to complete):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ktp = cw.ktp.Basic()\n",
    "key, text = ktp.next()\n",
    "ret = cw.capture_trace(scope, target, text, key)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "And then plot it. We'll need to do some preprocessing on the trace using `datashade()`, since trying to plot the trace normally will take far too long:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import holoviews as hv\n",
    "from holoviews.operation import decimate\n",
    "from holoviews.operation.datashader import datashade\n",
    "hv.extension('bokeh')\n",
    "datashade(hv.Curve(ret.wave)).opts(width=900, height=600)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You should see something like this:\n",
    "    \n",
    "![Stream mode 1](https://wiki.newae.com/images/8/89/Stream_mode_1.png)\n",
    "\n",
    "That distinctive part near the beginning is where everything is happening. Within that, we can see three separate sections:\n",
    "\n",
    "1. The target receiving the plaintext\n",
    "1. AES\n",
    "1. The target sending the ciphertext back to us\n",
    "\n",
    "Zoom into the middle section:\n",
    "\n",
    "![Stream mode 2](https://wiki.newae.com/images/9/96/Stream_mode_2.png)\n",
    "\n",
    "Then further into the beginning of AES:\n",
    "\n",
    "![Stream mode 3](https://wiki.newae.com/images/6/64/Stream_mode_3.png)\n",
    "\n",
    "And find a fairly unique area. You actually don't want to select the transition between receiving the plaintext and `get_pt()` here since that serial data is actually fairly noisy. You also don't want to select after where AES has started (hint: it may be good to refer back to PA_CPA_1 for what the start of AES looks like). Instead look for something like this:\n",
    "\n",
    "![Stream mode 4](https://wiki.newae.com/images/9/91/Stream_mode_4.png)\n",
    "\n",
    "Which looks like this zoomed in:\n",
    "\n",
    "![Stream mode 5](https://wiki.newae.com/images/a/aa/Stream_mode_5.png)\n",
    "\n",
    "Looking at our data from PA_CPA_1, we can see we're actually around the beginning of AES:\n",
    "\n",
    "![Stream mode 6](https://wiki.newae.com/images/d/dd/Stream_mode_7.png)\n",
    "\n",
    "Let's select a good starting point for our reference. Keep in mind that our reference will only be 128 samples long. In our case, we selected `1.444E5` as a reference. Don't worry too much about getting a perfect spot, you'll have a few oppotunities to check your reference and make sure it works fine. We'll also need to turn stream mode off."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "point = int(1.444E5)\n",
    "scope.adc.stream_mode = False"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now that we have a reference area, we're ready to start using the SAD module and finish the attack!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## The SAD Module"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As mentioned earlier, the SAD module will allow us to trigger based on the trace reference we just selected. The way it does this is also fairly simple: as trace data comes in it's compared to the reference using the SAD equation. If this comparison falls below a threshold, the trigger event occurs and we'll start capturing our wave. The SAD equation is as follows:\n",
    "\n",
    "$$S A D = \\sum _ { i = 1 } ^ { 128 } \\left| x _ { A D C , i } - x _ { p a t t e r n , i } \\right|$$\n",
    "\n",
    "which, as you can see, is just the sum of the absolute value of the difference between each point and the reference (a.k.a. the Sum of Absolute Difference). Basically, when the difference between the current trace data and the reference falls below a certain level, the SAD module knows it has reached the right spot.\n",
    "\n",
    "Now that you know how it works, let's setup the SAD module. We'll start by setting our reference:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.SAD.reference = ret.wave[point:point+128]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's see what it looks like:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "hv.Curve(scope.SAD.reference).opts(width=900, height=600)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "That should hopefully look fairly close to the area you selected. Next we'll set a threshold. You may have to experiment a bit with this value. If your trigger keeps timing out, try increasing the threshold. If it's selecting the wrong point or you're getting a lot of jitter, try lowering it. Otherwise, you may need to select a different reference trace. 5000 is typically a good starting point:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.SAD.threshold = 5000"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Next, we'll start the SAD module:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.SAD.start()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "And change our trigger module to be SAD. SAD outputs a rising edge trigger internally, so we'll need to change that as well:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.trigger.module = \"SAD\"\n",
    "scope.adc.basic_mode = \"rising_edge\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We'll only need to capture 5000 samples at most to break AES here:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.adc.samples=5000"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's print our scope and see what our settings look like:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(scope)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Before we get into the actual attack, let's also capture a few test traces and plot them. Make sure you let this loop go to completion, even if it's timing out; interrupting the capture can sometimes put the ChipWhisperer into an oddly configured state, requiring a power cycle (this is rare, but seems more common with SAD trigger)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from tqdm import tnrange\n",
    "project = cw.create_project(\"projects/Tutorial_B5\", overwrite = True)\n",
    "for i in tnrange(3, desc='Capturing traces'):\n",
    "    key, text = ktp.next()  # manual creation of a key, text pair can be substituted here\n",
    "    trace = cw.capture_trace(scope, target, text, key)\n",
    "    if trace is None:\n",
    "        continue\n",
    "    project.traces.append(trace)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If you got traces from that plot them. If not, go back and adjust your reference/threshold."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "hv.Curve(project.waves[0]).opts(width=900, height=600) * hv.Curve(project.waves[1]).opts(width=900, height=600) * hv.Curve(project.waves[2]).opts(width=900, height=600)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "These hopefully look good. Next, let's run our attack:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from tqdm import tnrange\n",
    "project = cw.create_project(\"projects/Tutorial_B5\", overwrite = True)\n",
    "for i in tnrange(100, desc='Capturing traces'):\n",
    "    key, text = ktp.next()  # manual creation of a key, text pair can be substituted here\n",
    "    trace = cw.capture_trace(scope, target, text, key)\n",
    "    if trace is None:\n",
    "        continue\n",
    "    project.traces.append(trace)\n",
    "project.save()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Analysis"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Analysis is super simple here: it's just a standard CPA attack at this point."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import chipwhisperer.analyzer as cwa\n",
    "leak_model = cwa.leakage_models.sbox_output\n",
    "attack = cwa.cpa(project, leak_model)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "results = attack.run(None, 100)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "And the result is:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(results)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Comparing to the correct key, you should find that you've successully conducted the attack:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(results.find_key(), \"\\n\", list(project.keys[0]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Conclusion"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In this tutorial we have learned to use two of the CW1200_ChipWhisperer-Pro's exclusive features stream mode and SAD Trigger. The stream feature allows us the continually stream and manually send plain text to the target to observe the encryption process. Then 128 sample points that make up a unique feature of the encryption process where chosen to activate the trigger during trace capture. These two features together can be used to break the AES encryption of a device without any help from the target. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Tests"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "assert results.find_key() == list(project.keys[0]), \"Failed to break key!\\nGot: {}\\nExp: {}\".format(results.find_key(), list(project.keys[0]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
